package faultHandler

import (
	"context"
	"encoding/json"
	"github.com/pkg/errors"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"goproject/api/v1alpha1"
	"goproject/chaos"
	"goproject/commonType"
	"goproject/k8s"
	"goproject/logger"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"os"
)

// 将primitive.D和primitive.E中的Value转换为更适合的类型
func convertValue(v interface{}) interface{} {
	switch val := v.(type) {
	case primitive.D:
		return convertDToMap(val)
	case primitive.A:
		return convertAToSlice(val)
	default:
		return val
	}
}

// 将primitive.D转换为map[string]interface{}
func convertDToMap(d primitive.D) map[string]interface{} {
	m := make(map[string]interface{})
	for _, e := range d {
		m[e.Key] = convertValue(e.Value)
	}
	return m
}

// 将primitive.A转换为[]interface{}
func convertAToSlice(a primitive.A) []interface{} {
	var slice []interface{}
	for _, v := range a {
		slice = append(slice, convertValue(v))
	}
	return slice
}

// 从来自 MongoDB 的定义生成 ChaosMesh 对象
func generateChaosMeshChaos(_ context.Context, fault commonType.Fault) (chaosMeshChaos v1alpha1.InnerObject, err error) {
	log := logger.GetLogger()
	// 输出故障类型定义
	log.Debugf("故障定义内容: %%#v %#v", fault.Define)
	// 创建 ChaosMesh 对象
	chaosMeshChaos, err = v1alpha1.CreateNewObject(v1alpha1.TemplateType(fault.ChaosType))
	if err != nil {
		err = errors.Wrapf(err, "创建 ChaosMesh 对象失败")
		return
	}
	log.Debugf("创建 ChaosMesh 对象成功: %%#v %#v", chaosMeshChaos)
	// 转换 MongoDB primitive.D / primitive.E / primitive.A 对象格式为 map[string]interface{}
	faultDefineMap := convertValue(fault.Define)
	log.Debugf("转换对象格式为 map[string]interface{} 成功: %%#v %#v", faultDefineMap)
	// 序列化为 JSON
	faultDefineBytes, err := json.Marshal(faultDefineMap)
	if err != nil {
		err = errors.Wrapf(err, "json 序列化失败")
		return
	}
	log.Debugf("json 序列化成功: %s", string(faultDefineBytes))
	// 反序列化为 ChaosMesh 对象
	err = json.Unmarshal(faultDefineBytes, chaosMeshChaos)
	if err != nil {
		err = errors.Wrapf(err, "json 反序列化失败")
		return
	}
	log.Debugf("json 反序列化成功: %%#v %#v", chaosMeshChaos)
	return
}

// 执行故障注入
func InjectFault(_ context.Context, fault commonType.Fault, podname string, namespace string) (v1alpha1.InnerObject, error) {

	// 生成 ChaosMesh 对象
	chaosMeshChaos, err := generateChaosMeshChaos(context.Background(), fault)
	if err != nil {
		err = errors.Wrapf(err, "生成 ChaosMesh 对象失败")
		return nil, err
	}
	// 设置故障定义的名字
	name := k8s.GenerateChaosName(podname, chaosMeshChaos.GetObjectKind().GroupVersionKind().Kind)
	chaosMeshChaos.SetName(name)

	// 获取pod的lables
	labels, err := getPodLabels(podname, namespace)
	if err != nil {
		err = errors.Wrapf(err, "获取Pod的标签失败")
		return nil, err
	}

	// 设置故障定义的Selectors
	err = chaos.SetPodSelectorFields(chaosMeshChaos, []string{namespace}, labels)
	if err != nil {
		err = errors.Wrapf(err, "设置故障定义的Selectors失败")
		return nil, err

	}
	// 注入故障
	k8s.InjectChaos(chaosMeshChaos)
	return chaosMeshChaos, nil
}

// 根据podname与namespace获取pod的labels
func getPodLabels(podname string, namespace string) (map[string]string, error) {
	// 创建Kubernetes客户端
	clientset, err := InitK8sClient()
	if err != nil {
		return nil, err
	}

	// 获取指定命名空间中的Pod
	pod, err := clientset.CoreV1().Pods(namespace).Get(context.TODO(), podname, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}

	// 返回Pod的标签
	return pod.Labels, nil
}

func InitK8sClient() (*kubernetes.Clientset, error) {
	config, err := rest.InClusterConfig()
	if err != nil {
		kubeconfig := os.Getenv("KUBECONFIG")
		if kubeconfig == "" {
			kubeconfig = os.Getenv("HOME") + "/.kube/config"
		}
		config, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
		if err != nil {
			return nil, err
		}
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return clientset, nil
}
